/**
 * 
 */
package de.htwsaar.smog.rest;

import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import de.htwsaar.smog.dao.MeasurementRepository;
import de.htwsaar.smog.exceptions.MeasurementNotFoundException;
import de.htwsaar.smog.model.Measurement;

/**
 * @author	Thomas Schoenfeld, Michael Oehm
 * @date	2015-02-14
 * @version	20150214_01
 *
 * Class RestApiHandler implements the REST API.  
 * This class accesses the db content via the interface MeasurementRepository. 
 * It also could directly access the db through inheritance from Repository, 
 * but our approach allows us the integration of exception handling and logging.
 * @param <MeasurementService>
 */
@Controller
@RestController
@RequestMapping("/measurements")
public class RestApiHandler<MeasurementService> extends AbstractRestHandler {

	//Dependency Injection:
	
	@Autowired
	private MeasurementRepository measurementRepository;
	@Autowired
	private MongoTemplate mongoTemplate;
	
	@RequestMapping(value = "sensorId/{sensorId}", method = RequestMethod.GET)
	public @ResponseBody List<Measurement> findBySensorId(@PathVariable("sensorId") String sensorId) {
		return this.measurementRepository.findBySensorId(sensorId);
	}	

	@RequestMapping(value = "location/{location}", method = RequestMethod.GET)
	public @ResponseBody List<Measurement> findByLocation(@PathVariable("location") String location) {
		return this.measurementRepository.findByLocation(location);
	}
	
	@RequestMapping(value = "longitude/{longitude}", method = RequestMethod.GET)
	public @ResponseBody List<Measurement> findByLongitude(@PathVariable("longitude") String longitude) {
		return this.measurementRepository.findByLongitude(longitude);
	}	

	@RequestMapping(value = "latitude/{latitude}", method = RequestMethod.GET)
	public @ResponseBody List<Measurement> findByLatitude(@PathVariable("latitude") String latitude) {
		return this.measurementRepository.findByLatitude(latitude);
	}
	
	@RequestMapping(value = "type/{type}", method = RequestMethod.GET)
	public @ResponseBody List<Measurement> findByType(@PathVariable("type") String type) {
		return this.measurementRepository.findByType(type);
	}
		
	@RequestMapping(value = "time/{time}", method = RequestMethod.GET)
	public @ResponseBody List<Measurement> findByTime(@PathVariable("time") Date time) {
		return this.measurementRepository.findByTime(time);
	}
	
	@RequestMapping(value = "value/{value}", method = RequestMethod.GET)
	public @ResponseBody List<Measurement> findByValue(@PathVariable("value") int value) {
		return this.measurementRepository.findByValue(value);
	}
		
	@RequestMapping("all")
	public @ResponseBody List<Measurement> findAll() {
		return this.measurementRepository.findAll();
	}
	
	@RequestMapping("newest")
	public @ResponseBody List<Measurement> findNewest() {

		TypedAggregation<Measurement> agg = new TypedAggregation<Measurement>(Measurement.class, 
				Aggregation.sort(Direction.ASC, "sensorId","time"),
				Aggregation.group("sensorId")
				    .last("sensorId").as("sensorId")
				    .last("location").as("location")
				    .last("longitude").as("longitude")
				    .last("latitude").as("latitude")
				    .last("type").as("type")
				    .last("time").as("time")
				    .last("value").as("value")
				);
		//BasicQuery query = new BasicQuery("{ $sort: { sensor_id: 1, time: 1}}, {$group: {_id: '$sensor_id', sensor_id: { $last: '$sensor_id'}, location: {$last: '$location'}, longitude: {$last: '$longitude'}, latitude: {$last: '$latitude'}, type: {$last: '$type'}, time: {$last: '$time'}, value: { $last: '$value' }}}");
		AggregationResults<Measurement> result =  mongoTemplate.aggregate(agg, Measurement.class); 
		List <Measurement> resultList = result.getMappedResults();
		
		return resultList;
	}
	
	@ExceptionHandler
	@ResponseStatus(HttpStatus.NOT_FOUND)
	public void handleSampleNotFound(MeasurementNotFoundException ex) {}
}
